home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Peter Lewis / TCPOOExample / TCP Libraries / TCPOOConnections.unit < prev    next >
Encoding:
Text File  |  1993-06-30  |  18.3 KB  |  823 lines  |  [TEXT/PJMM]

  1. unit TCPOOConnections;
  2.  
  3. { TCPOOConnections © Peter Lewis, April 1993 }
  4.  
  5. interface
  6.  
  7.     uses
  8.         TCPTypes, TCPStuff, MyTypes;
  9.  
  10.     const
  11.         tooManyConnections = -23099;
  12.         timeoutError = -23098;
  13.         failedToOpenError = 23097;
  14.  
  15. { Sequence: }
  16. { new(obj) }
  17. { oe:=obj.Create }
  18. { if oe=noErr then begin }
  19. {   do stuff}
  20. { end; }
  21. { obj.Destroy }
  22.  
  23.     type
  24.         ConnectionBaseObject = object
  25.                 timetodie: boolean; { Set this to have Destroy called at the end of HandleConnection }
  26.                 connection_index: integer; { private! }
  27.                 closedone, terminatedone: boolean;
  28.                 heartbeat_period: longInt; { set to <=0 to disable heartbeats }
  29.                 heartbeat_time: longInt; { set to time of next heartbeat, it is automatically incrememnted by the period }
  30. { To enable heartbeats, set heartbeat_time to TickCount, and heartbeat_period to the period in ticks }
  31.                 timeout_time: longInt; { set to time to timeout TickCount }
  32.                 function Create: OSErr;
  33.                 procedure Destroy;
  34.                 procedure HeartBeat;
  35.                 procedure Failed (oe: OSErr);
  36.                 procedure Timeout;
  37.                 procedure Terminate;
  38.                 procedure Close;
  39.                 function HandleConnection: boolean;
  40.             end;
  41.         GeneralSearchObject = object(ConnectionBaseObject)
  42.                 hip: ptr; { private! }
  43.                 function Create: OSErr;
  44.                 override;
  45.                 procedure Destroy;
  46.                 override;
  47.             end;
  48.         NameSearchObject = object(GeneralSearchObject)
  49.                 ip: longInt;
  50.                 function HandleConnection: boolean;
  51.                 override;
  52.                 function FindName (hostIP: longInt): OSErr;
  53.                 procedure FoundName (name: str255; error: OSErr);
  54.             end;
  55.         AddressSearchObject = object(GeneralSearchObject)
  56.                 function HandleConnection: boolean;
  57.                 override;
  58.                 function FindAddress (hostName: str255): OSErr;
  59.                 procedure FoundAddress (ip: longInt);
  60.             end;
  61.         UDPObject = object(ConnectionBaseObject)
  62.                 udpcp: UDPConnectionPtr;
  63.                 localport: integer;
  64.                 function CreatePort (buffer_size: longInt; port: integer): OSErr;
  65.                 procedure Close;
  66.                 override;
  67.                 procedure Terminate;
  68.                 override;
  69.                 procedure Destroy;
  70.                 override;
  71.                 function HandleConnection: boolean;
  72.                 override;
  73.                 procedure PacketAvailable (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer);
  74.                 procedure PacketsAvailable (count: integer);
  75.                 function SendPacket (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer; checksum: boolean): OSErr;
  76.             end;
  77.         statusType = (CS_Opening, CS_Established, CS_Closing);
  78.         ConnectionObject = object(ConnectionBaseObject)
  79.                 tcpc: TCPConnectionPtr;
  80.                 status: statusType;
  81.                 procedure Destroy;
  82.                 override;
  83.                 function HandleConnection: boolean;
  84.                 override;
  85.                 function NewPassiveConnection (buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer): OSErr;
  86.                 function NewActiveConnection (buffersize: longInt; remotehost: longInt; remoteport: integer): OSErr;
  87.                 procedure Close;
  88.                 override;
  89.                 procedure Terminate;
  90.                 override;
  91.                 procedure Established;
  92.                 procedure Closing;
  93.                 procedure CharsAvailable (count: longInt);
  94.             end;
  95.         LineConnectionObject = object(ConnectionObject)
  96.                 crlf: CRLFTypes;
  97.                 buffer: str255;
  98.                 function Create: OSErr;
  99.                 override;
  100.                 procedure SendLine (s: str255);
  101.                 procedure LineAvailable (line: str255);
  102.                 procedure CharsAvailable (count: longInt);
  103.                 override;
  104.             end;
  105.  
  106.     function InitConnections: OSErr;
  107.     procedure FinishConnections;
  108.     function HandleConnections (maxtime: integer): boolean;
  109.     procedure ConnectionsAddrToString (ip: longInt; var addrStr: str255);
  110.     function ConnectionsAddrToStr (ip: longInt): str255;
  111.     function ConnectionsStrToAddr (s: str255; var addr: longInt): boolean;
  112. { You probably wont need these: }
  113.     procedure TerminateConnections;
  114.     procedure CloseConnections;
  115.     function CanQuit: boolean;
  116.  
  117. implementation
  118.  
  119.     const
  120.         TCPCMagic = 'TCPC';
  121.         TCPCBadMagic = 'badc';
  122.  
  123.     const  { Tuning parameters }
  124.         max_connections = 64;
  125.         TO_FindAddress = 40 * 60;
  126.         TO_FindName = 40 * 60;
  127.         TO_ActiveOpen = 20 * 60;
  128.         TO_Closing = longInt(2) * 60 * 60;
  129.         TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  130.  
  131.     type
  132.         myHostInfo = record
  133.                 hi: hostInfo;
  134.                 done: signedByte;
  135.             end;
  136.         myHIP = ^myHostInfo;
  137.  
  138.     type
  139.         connectionRecord = record
  140.                 obj: ConnectionBaseObject;
  141.             end;
  142.  
  143.     var
  144.         connections: array[1..max_connections] of connectionRecord;
  145.         connectionItem: integer;
  146.         dnrptr: ptr;
  147.  
  148.     function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  149.     begin
  150.         if con = nil then
  151.             MyTCPState := T_Closed
  152.         else
  153.             MyTCPState := TCPState(con);
  154.     end;
  155.  
  156. {$S Init}
  157.     function InitConnections: OSErr;
  158.         var
  159.             oe: OSErr;
  160.             i: integer;
  161.     begin
  162.         icmp_sent_out := 0;
  163.         icmp_got_back := 0;
  164.         connectionItem := 1;
  165.         for i := 1 to max_connections do
  166.             connections[i].obj := nil;
  167.         oe := TCPInit;
  168.         if oe = noErr then begin
  169.             oe := TCPOpenResolver(dnrptr);
  170.             if oe <> noErr then
  171.                 TCPFinish;
  172.         end;
  173.         InitConnections := oe;
  174.     end;
  175. {$S}
  176.  
  177. {$S Term}
  178.     procedure TerminateConnections;
  179.         var
  180.             i: integer;
  181.     begin
  182.         for i := 1 to max_connections do
  183.             if connections[i].obj <> nil then begin
  184.                 if not connections[i].obj.terminatedone then
  185.                     connections[i].obj.Terminate;
  186.             end;
  187.     end;
  188. {$S}
  189.  
  190. {$S Term}
  191.     procedure CloseConnections;
  192.         var
  193.             i: integer;
  194.     begin
  195.         for i := 1 to max_connections do
  196.             if connections[i].obj <> nil then begin
  197.                 connections[i].obj.Close;
  198.             end;
  199.     end;
  200. {$S}
  201.  
  202. {$S Term}
  203.     function CanQuit: boolean;
  204.         var
  205.             i: integer;
  206.     begin
  207.         CanQuit := icmp_sent_out = icmp_got_back;
  208.         for i := 1 to max_connections do
  209.             if connections[i].obj <> nil then begin
  210.                 CanQuit := false;
  211.                 leave;
  212.             end;
  213.     end;
  214.  
  215. {$S Term}
  216.     procedure FinishConnections;
  217.         var
  218.             dummy: boolean;
  219.             er: eventRecord;
  220.     begin
  221.         while not CanQuit do begin
  222.             TerminateConnections;
  223.             if HandleConnections(3) then begin
  224.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  225.             end
  226.             else
  227.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  228.         end;
  229.         TCPCloseResolver(dnrptr);
  230.         TCPFinish;
  231.     end;
  232. {$S}
  233.  
  234.     function ConnectionBaseObject.Create: OSErr;
  235.         var
  236.             i: integer;
  237.             oe: OSErr;
  238.     begin
  239.         i := 1;
  240.         while (i <= max_connections) & (connections[i].obj <> nil) do
  241.             i := i + 1;
  242.         if i <= max_connections then begin
  243.             timetodie := false;
  244.             connection_index := i;
  245.             connections[i].obj := self;
  246.             heartbeat_period := 0;
  247.             heartbeat_time := 0;
  248.             timeout_time := maxLongInt;
  249.             closedone := false;
  250.             terminatedone := false;
  251.             oe := noErr;
  252.         end
  253.         else begin
  254.             connection_index := -1;
  255.             oe := tooManyConnections;
  256.         end;
  257.         Create := oe;
  258.     end;
  259.  
  260.     procedure ConnectionBaseObject.Destroy;
  261.     begin
  262.         if connection_index > 0 then
  263.             connections[connection_index].obj := nil;
  264.         dispose(self);
  265.     end;
  266.  
  267.     procedure ConnectionBaseObject.HeartBeat;
  268.     begin
  269.     end;
  270.  
  271.     procedure ConnectionBaseObject.Failed (oe: OSErr);
  272.     begin
  273.         timetodie := true;
  274.     end;
  275.  
  276.     procedure ConnectionBaseObject.Timeout;
  277.     begin
  278.         Failed(timeoutError);
  279.     end;
  280.  
  281.     procedure ConnectionBaseObject.Terminate;
  282.     begin
  283.         terminatedone := true;
  284.     end;
  285.  
  286.     procedure ConnectionBaseObject.Close;
  287.     begin
  288.         closedone := true;
  289.     end;
  290.  
  291.     function ConnectionBaseObject.HandleConnection: boolean;
  292.         var
  293.             now: longInt;
  294.     begin
  295.         HandleConnection := false;
  296.         now := TickCount;
  297.         if now > timeout_time then begin
  298.             timeout_time := maxLongInt;
  299.             Timeout;
  300.             HandleConnection := true;
  301.         end
  302.         else if (heartbeat_period > 0) & (now >= heartbeat_time) then begin
  303.             HeartBeat;
  304.             heartbeat_time := heartbeat_time + heartbeat_period;
  305.             HandleConnection := true;
  306.         end;
  307.     end;
  308.  
  309.     function GeneralSearchObject.Create: OSErr;
  310.         var
  311.             oe: OSErr;
  312.     begin
  313.         oe := inherited Create;
  314.         hip := nil;
  315.         if oe = noErr then begin
  316.             hip := NewPtr(SizeOf(myHostInfo));
  317.             oe := MemError;
  318.         end;
  319.         Create := oe;
  320.     end;
  321.  
  322.     procedure GeneralSearchObject.Destroy;
  323.     begin
  324.         if hip <> nil then begin
  325.             DisposePtr(hip);
  326.             hip := nil;
  327.         end;
  328.         inherited Destroy;
  329.     end;
  330.  
  331.     function AddressSearchObject.FindAddress (hostName: str255): OSErr;
  332.         var
  333.             oe: OSErr;
  334.     begin
  335.         oe := Create;
  336.         if oe = noErr then begin
  337.             myHIP(hip)^.done := 0;
  338.             oe := TCPStrToAddr(dnrptr, hostName, myHIP(hip)^.hi, myHIP(hip)^.done);
  339.             if oe = cacheFault then begin
  340.                 timeout_time := TickCount + TO_FindAddress;
  341.                 oe := noErr;
  342.             end
  343.             else begin
  344.                 myHIP(hip)^.done := -1;
  345.                 myHIP(hip)^.hi.rtnCode := oe;
  346.             end;
  347.         end;
  348.         if oe <> noErr then
  349.             Destroy;
  350.         FindAddress := oe;
  351.     end;
  352.  
  353.     procedure AddressSearchObject.FoundAddress (ip: longInt);
  354.     begin
  355.     end;
  356.  
  357.     function AddressSearchObject.HandleConnection: boolean;
  358.     begin
  359.         with myHIP(hip)^, hi do begin
  360.             if rtnCode = noErr then begin
  361.                 FoundAddress(addrs[1]);
  362.                 timetodie := true;
  363.                 HandleConnection := true;
  364.             end
  365.             else if done <> 0 then begin
  366.                 Failed(rtnCode);
  367.                 timetodie := true;
  368.                 HandleConnection := true;
  369.             end
  370.             else
  371.                 HandleConnection := inherited HandleConnection;
  372.         end; {with}
  373.     end;
  374.  
  375.     function NameSearchObject.FindName (hostIP: longInt): OSErr;
  376.         var
  377.             oe: OSErr;
  378.             hostname: str255;
  379.     begin
  380.         ip := hostIP;
  381.         oe := Create;
  382.         if oe = noErr then begin
  383.             myHIP(hip)^.done := 0;
  384.             oe := TCPAddrToName(dnrptr, hostIP, myHIP(hip)^.hi, myHIP(hip)^.done);
  385.             if oe = cacheFault then begin
  386.                 timeout_time := TickCount + TO_FindName;
  387.                 oe := noErr;
  388.             end
  389.             else begin
  390.                 myHIP(hip)^.done := -1;
  391.                 myHIP(hip)^.hi.rtnCode := oe;
  392.             end;
  393.         end;
  394.         if oe <> noErr then begin
  395.             TCPAddrToStr(dnrptr, hostIP, hostname);
  396.             FoundName(hostname, oe);
  397.         end;
  398.         if oe <> noErr then
  399.             Destroy;
  400.         FindName := oe;
  401.     end;
  402.  
  403.     procedure NameSearchObject.FoundName (name: str255; error: OSErr);
  404.     begin
  405.     end;
  406.  
  407.     function NameSearchObject.HandleConnection: boolean;
  408.     begin
  409.         with myHIP(hip)^, hi do begin
  410.             if done <> 0 then begin
  411.                 if rtnCode = noErr then begin
  412.                     SanitizeHostName(rtnHostName);
  413.                     FoundName(rtnHostName, noErr);
  414.                     timetodie := true;
  415.                     HandleConnection := true;
  416.                 end
  417.                 else begin
  418.                     TCPAddrToStr(dnrptr, ip, rtnHostName);
  419.                     FoundName(rtnHostName, rtnCode);
  420.                     timetodie := true;
  421.                     HandleConnection := true;
  422.                 end
  423.             end
  424.             else
  425.                 HandleConnection := inherited HandleConnection;
  426.         end; {with}
  427.     end;
  428.  
  429.     procedure ConnectionObject.Established;
  430.     begin
  431.     end;
  432.  
  433.     procedure ConnectionObject.Closing;
  434.     begin
  435.     end;
  436.  
  437.     procedure ConnectionObject.CharsAvailable (count: longInt);
  438.     begin
  439.     end;
  440.  
  441.     procedure ConnectionObject.Destroy;
  442.         var
  443.             tmp_tcpc: TCPConnectionPtr;
  444.             oe: OSErr;
  445.     begin
  446.         if tcpc <> nil then begin
  447.             oe := TCPAbort(tcpc);
  448.             tmp_tcpc := tcpc;
  449.             oe := TCPRelease(tmp_tcpc);
  450.         end;
  451.         inherited Destroy;
  452.     end;
  453.  
  454.     function ConnectionObject.NewPassiveConnection (buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer): OSErr;
  455.         var
  456.             oe: OSErr;
  457.             tmp_tcpc: TCPConnectionPtr;
  458.     begin
  459.         oe := Create;
  460.         if oe = noErr then begin
  461.             oe := TCPPassiveOpen(tmp_tcpc, buffersize, localPort, remotehost, remoteport, nil);
  462.             tcpc := tmp_tcpc;
  463.             status := CS_Opening;
  464.             timeout_time := TickCount + TO_PassiveOpen;
  465.         end;
  466.         if oe <> noErr then begin
  467.             tcpc := nil;
  468.             Destroy;
  469.         end;
  470.         NewPassiveConnection := oe;
  471.     end;
  472.  
  473.     function ConnectionObject.NewActiveConnection (buffersize: longInt; remotehost: longInt; remoteport: integer): OSErr;
  474.         var
  475.             oe: OSErr;
  476.             tmp_tcpc: TCPConnectionPtr;
  477.     begin
  478.         oe := Create;
  479.         if oe = noErr then begin
  480.             oe := TCPActiveOpen(tmp_tcpc, buffersize, 0, remotehost, remoteport, nil);
  481.             tcpc := tmp_tcpc;
  482.             status := CS_Opening;
  483.             timeout_time := TickCount + TO_ActiveOpen;
  484.         end;
  485.         if oe <> noErr then begin
  486.             tcpc := nil;
  487.             Destroy;
  488.         end;
  489.         NewActiveConnection := oe;
  490.     end;
  491.  
  492.     procedure ConnectionObject.Close;
  493.         var
  494.             oe: OSErr;
  495.     begin
  496.         if not closedone and (tcpc <> nil) then begin
  497.             oe := TCPClose(tcpc, nil);
  498.             closedone := true;
  499.         end;
  500.     end;
  501.  
  502.     procedure ConnectionObject.Terminate;
  503.         var
  504.             oe: OSErr;
  505.     begin
  506.         if not terminatedone and (tcpc <> nil) then begin
  507.             oe := TCPAbort(tcpc);
  508.             terminatedone := true;
  509.         end;
  510.     end;
  511.  
  512.  
  513.     function ConnectionObject.HandleConnection: boolean;
  514.         var
  515.             didit: boolean;
  516.             count: longInt;
  517.             state: TCPStateType;
  518.     begin
  519.         didit := false;
  520.         state := MyTCPState(tcpc);
  521.         case status of
  522.             CS_Opening:  begin
  523.                 case state of
  524.                     T_WaitingForOpen, T_Opening, T_Listening: 
  525.                         ;
  526.                     T_Established:  begin
  527.                         Established;
  528.                         status := CS_Established;
  529.                         timeout_time := maxLongInt;
  530.                         didit := true;
  531.                     end;
  532.                     T_PleaseClose, T_Closing, T_Closed:  begin
  533.                         didit := true;
  534.                         Failed(failedToOpenError);
  535.                         timetodie := true;
  536.                     end;
  537.                     otherwise
  538.                         ;
  539.                 end; {case }
  540.             end;
  541.             CS_Established:  begin
  542.                 case state of
  543.                     T_Established:  begin
  544.                         count := TCPCharsAvailable(tcpc);
  545.                         if count > 0 then begin
  546.                             CharsAvailable(count);
  547.                             didit := true;
  548.                         end;
  549.                     end;
  550.                     T_PleaseClose, T_Closing:  begin
  551.                         count := TCPCharsAvailable(tcpc);
  552.                         if count > 0 then begin
  553.                             CharsAvailable(count);
  554.                             didit := true;
  555.                         end
  556.                         else begin
  557.                             Closing;
  558.                             status := CS_Closing;
  559.                             timeout_time := TickCount + TO_Closing;
  560.                             didit := true;
  561.                         end;
  562.                     end;
  563.                     T_Closed:  begin
  564.                         Closing;
  565.                         status := CS_Closing;
  566.                         timeout_time := TickCount + TO_Closing;
  567.                         didit := true;
  568.                     end;
  569.                     otherwise
  570.                         ;
  571.                 end;
  572.             end;
  573.             CS_Closing:  begin
  574.                 case state of
  575.                     T_PleaseClose, T_Closing, T_Established:  begin
  576.                         count := TCPCharsAvailable(tcpc);
  577.                         if count > 0 then begin
  578.                             CharsAvailable(count);
  579.                             didit := true;
  580.                         end;
  581.                     end;
  582.                     T_Closed:  begin
  583.                         timetodie := true;
  584.                         didit := true;
  585.                     end;
  586.                     otherwise
  587.                         ;
  588.                 end;
  589.             end;
  590.             otherwise
  591.                 ;
  592.         end;
  593.         if not didit then
  594.             didit := inherited HandleConnection;
  595.         HandleConnection := didit;
  596.     end;
  597.  
  598.     function LineConnectionObject.Create: OSErr;
  599.     begin
  600.         crlf := CL_CRLF;
  601.         buffer := '';
  602.         Create := inherited Create;
  603.     end;
  604.  
  605.     procedure LineConnectionObject.SendLine (s: str255);
  606.         var
  607.             oe: OSErr;
  608.     begin
  609.         if crlf <> CL_LF then
  610.             s := concat(s, cr);
  611.         if crlf <> CL_CR then
  612.             s := concat(s, lf);
  613.         oe := TCPSendAsync(tcpc, @s[1], length(s), true, nil);
  614.     end;
  615.  
  616.     procedure LineConnectionObject.LineAvailable (line: str255);
  617.     begin
  618.     end;
  619.  
  620.     procedure LineConnectionObject.CharsAvailable (count: longInt);
  621.         var
  622.             oe: OSErr;
  623.             pos: longInt;
  624.             gotlf: boolean;
  625.             termchar: char;
  626.             s: str255;
  627.     begin
  628. {$PUSH}
  629. {$R-}
  630.         if crlf = CL_CR then
  631.             termchar := cr
  632.         else
  633.             termchar := lf;
  634.         s := buffer;
  635.         pos := length(s);
  636.         oe := TCPReceiveUpTo(tcpc, ord(termchar), 0, @s[1], 255, pos, gotlf);
  637.         s[0] := chr(pos);
  638.         buffer := s;
  639.         if gotlf or (length(buffer) = 255) then begin
  640.             if (length(buffer) > 0) and (buffer[length(buffer)] = lf) then
  641.                 buffer[0] := chr(length(buffer) - 1);
  642.             if (length(buffer) > 0) and (buffer[length(buffer)] = cr) then
  643.                 buffer[0] := chr(length(buffer) - 1);
  644.             LineAvailable(buffer);
  645.             buffer := '';
  646.         end;
  647. {$POP}
  648.     end;
  649.  
  650.     function UDPObject.CreatePort (buffer_size: longInt; port: integer): OSErr;
  651.         var
  652.             oe: OSErr;
  653.             tmp_udpcp: UDPConnectionPtr;
  654.     begin
  655.         oe := Create;
  656.         if oe = noErr then begin
  657.             oe := UDPCreate(tmp_udpcp, buffer_size, port);
  658.             udpcp := tmp_udpcp;
  659.             localport := port;
  660.             timeout_time := maxLongInt;
  661.         end;
  662.         if oe <> noErr then begin
  663.             udpcp := nil;
  664.             Destroy;
  665.         end;
  666.         CreatePort := oe;
  667.     end;
  668.  
  669.     procedure UDPObject.Terminate;
  670.     begin
  671.         Close;
  672.     end;
  673.  
  674.     procedure UDPObject.Close;
  675.         var
  676.             tmp_udpcp: UDPConnectionPtr;
  677.             oe: OSErr;
  678.     begin
  679.         if udpcp <> nil then begin
  680.             tmp_udpcp := udpcp;
  681.             oe := UDPRelease(tmp_udpcp);
  682.             udpcp := nil;
  683.         end;
  684.         timetodie := true;
  685.     end;
  686.  
  687.     procedure UDPObject.Destroy;
  688.     begin
  689.         if udpcp <> nil then begin
  690.             Close;
  691.         end;
  692.         inherited Destroy;
  693.     end;
  694.  
  695.     procedure UDPObject.PacketAvailable (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer);
  696.     begin
  697.     end;
  698.  
  699.     procedure UDPObject.PacketsAvailable (count: integer);
  700.         var
  701.             oe: OSErr;
  702.             remoteIP: longInt;
  703.             remoteport: integer;
  704.             datap: ptr;
  705.             datalen: integer;
  706.             u: UDPConnectionPtr;
  707.     begin
  708.         oe := UDPRead(udpcp, 1, remoteIP, remoteport, datap, datalen);
  709.         if oe = noErr then begin
  710.             u := udpcp;
  711.             PacketAvailable(remoteIP, remoteport, datap, datalen);
  712. { self may be nil now }
  713.             oe := UDPReturnBuffer(u, datap);
  714.         end;
  715.     end;
  716.  
  717.     function UDPObject.SendPacket (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer; checksum: boolean): OSErr;
  718.     begin
  719.         SendPacket := UDPWrite(udpcp, remoteIP, remoteport, datap, datalen, checksum);
  720.     end;
  721.  
  722.     function UDPObject.HandleConnection: boolean;
  723.         var
  724.             didit: boolean;
  725.             count: longInt;
  726.     begin
  727.         didit := false;
  728.         if udpcp <> nil then begin
  729.             count := UDPDatagramsAvailable(udpcp);
  730.             if count > 0 then begin
  731.                 PacketsAvailable(count);
  732.                 didit := true;
  733.             end;
  734.         end;
  735.         if not didit then
  736.             didit := inherited HandleConnection;
  737.         HandleConnection := didit;
  738.     end;
  739.  
  740.     function HandleConnections (maxtime: integer): boolean;
  741.         var
  742.             oci: integer;
  743.             did, didthis: boolean;
  744.             start: longInt;
  745.     begin
  746.         start := TickCount;
  747.         oci := connectionItem;
  748.         did := false;
  749.         repeat
  750.             if connections[connectionItem].obj <> nil then begin
  751.                 repeat
  752.                     didthis := connections[connectionItem].obj.HandleConnection;
  753.                     if (connections[connectionItem].obj <> nil) & (connections[connectionItem].obj.timetodie) then
  754.                         connections[connectionItem].obj.Destroy;
  755.                     if didthis then
  756.                         did := true;
  757.                 until not didthis or (connections[connectionItem].obj = nil) or (TickCount >= start + maxtime);
  758.             end;{if}
  759.             if connectionItem = max_connections then
  760.                 connectionItem := 1
  761.             else
  762.                 connectionItem := connectionItem + 1;
  763.         until did or (oci = connectionItem);
  764.         HandleConnections := did;
  765.     end;
  766.  
  767.     function ConnectionsStrToAddr (s: str255; var addr: longInt): boolean;
  768.         var
  769.             good: boolean;
  770.         procedure Get1;
  771.             var
  772.                 b: integer;
  773.         begin
  774.             if (length(s) = 0) | not (s[1] in ['0'..'9']) then
  775.                 good := false
  776.             else begin
  777.                 b := ord(s[1]) - 48;
  778.                 s := copy(s, 2, 255);
  779.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  780.                     b := b * 10 + ord(s[1]) - 48;
  781.                     s := copy(s, 2, 255);
  782.                 end;
  783.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  784.                     b := b * 10 + ord(s[1]) - 48;
  785.                     s := copy(s, 2, 255);
  786.                 end;
  787.                 if (s <> '') & (s[1] = '.') then begin
  788.                     s := copy(s, 2, 255);
  789.                 end;
  790.                 if b > 255 then begin
  791.                     good := false;
  792.                     b := 0; { avoid overflow error? }
  793.                 end;
  794.                 addr := BOR(BSL(addr, 8), b);
  795.             end;
  796.         end;
  797.     begin
  798.         good := true;
  799.         addr := 0;
  800.         Get1;
  801.         Get1;
  802.         Get1;
  803.         Get1;
  804.         good := good & (s = '');
  805.         if not good then
  806.             addr := 0;
  807.         ConnectionsStrToAddr := good;
  808.     end;
  809.  
  810.     procedure ConnectionsAddrToString (ip: longInt; var addrStr: str255);
  811.     begin
  812.         TCPAddrToStr(dnrptr, ip, addrStr);
  813.     end;
  814.  
  815.     function ConnectionsAddrToStr (ip: longInt): str255;
  816.         var
  817.             s: str255;
  818.     begin
  819.         TCPAddrToStr(dnrptr, ip, s);
  820.         ConnectionsAddrToStr := s;
  821.     end;
  822.  
  823. end.